package com.tsfyun.scm.service.impl.system;

import cn.hutool.core.collection.CollectionUtil;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.tsfyun.common.base.config.OrikaBeanMapper;
import com.tsfyun.common.base.exception.ServiceException;
import com.tsfyun.common.base.extension.ServiceImpl;
import com.tsfyun.common.base.util.StringUtils;
import com.tsfyun.common.base.util.TsfPreconditions;
import com.tsfyun.scm.dto.system.DepartmentDTO;
import com.tsfyun.scm.entity.system.SysDepartment;
import com.tsfyun.scm.mapper.system.SysDepartmentMapper;
import com.tsfyun.scm.service.system.ISysDepartmentService;
import com.tsfyun.scm.service.user.IPersonService;
import com.tsfyun.scm.util.UIDepartment;
import com.tsfyun.scm.vo.system.DepartmentVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;
import tk.mybatis.mapper.weekend.WeekendSqls;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class SysDepartmentServiceImpl extends ServiceImpl<SysDepartment> implements ISysDepartmentService {

    @Autowired
    private OrikaBeanMapper beanMapper;

    @Autowired
    private SysDepartmentMapper sysDepartmentMapper;

    @Autowired
    private IPersonService personService;

    @Override
    public List<UIDepartment> getAllDepartmentTree(boolean isTree) {
        //获取所有的部门
        List<SysDepartment> sysDepartments = super.list();
        if(CollectionUtil.isEmpty(sysDepartments)) {
            return null;
        }
        return isTree ? UIDepartment.buildTree(sysDepartments) : beanMapper.mapAsList(sysDepartments,UIDepartment.class);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void add(DepartmentDTO dto) {
        if(0 == dto.getParentId()) {
            //一级部门
            dto.setParentId(null);
        }
        SysDepartment sysDepartment = beanMapper.map(dto,SysDepartment.class);
        //校验父级部门是否存在
        if(Objects.nonNull(dto.getParentId())) {
            TsfPreconditions.checkArgument(Objects.nonNull(super.getById(dto.getParentId())),new ServiceException("上级部门不存在"));
        }
        try {
            sysDepartment.setCode(dto.getCode());
            super.saveNonNull(sysDepartment);
        } catch (DuplicateKeyException e) {
            if(e.getMessage().contains("code")) {
                throw new ServiceException("编码已经存在");
            } else if(e.getMessage().contains("name")) {
                throw new ServiceException("名称已经存在");
            } else {
                throw new ServiceException("保存失败，请检查数据是否填写正确");
            }
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void edit(DepartmentDTO dto) {
        SysDepartment sysDepartment = super.getById(dto.getId());
        TsfPreconditions.checkArgument(Objects.nonNull(sysDepartment),new ServiceException("部门信息不存在"));
        //校验父级部门是否存在
        if(Objects.nonNull(dto.getParentId())) {
            TsfPreconditions.checkArgument(Objects.nonNull(super.getById(dto.getParentId())),new ServiceException("上级部门不存在"));
        }
        SysDepartment update = new SysDepartment();
        update.setCode(StringUtils.null2EmptyWithTrim(dto.getCode()));
        update.setName(StringUtils.null2EmptyWithTrim(dto.getName()));
        update.setSort(dto.getSort());
        try {
            sysDepartmentMapper.updateByExampleSelective(update, Example.builder(SysDepartment.class).where(WeekendSqls.<SysDepartment>custom()
                    .andEqualTo(SysDepartment::getId, dto.getId())).build());
        } catch (DuplicateKeyException e) {
            if(e.getMessage().contains("code")) {
                throw new ServiceException("编码已经存在");
            } else if(e.getMessage().contains("name")) {
                throw new ServiceException("名称已经存在");
            } else {
                throw new ServiceException("保存失败，请检查数据是否填写正确");
            }
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delete(Long id) {
        //1.删除部门时，该部门下存在员工，不允许删除
        //2.删除父级部门时，该父级部门下面存在子部门，不允许删除
        SysDepartment sysDepartment = super.getById(id);
        TsfPreconditions.checkArgument(Objects.nonNull(sysDepartment),new ServiceException("部门信息不存在"));
        int personCount = personService.countByDepartmentId(id);
        TsfPreconditions.checkArgument(personCount < 1,new ServiceException("该部门下面存在员工，不允许删除"));

        SysDepartment condition = new SysDepartment();
        condition.setParentId(id);
        TsfPreconditions.checkArgument(super.count(condition) < 1,new ServiceException("该部门下面存在子部门，不允许删除"));
        try {
            super.removeById(id);
        } catch (DataIntegrityViolationException e) {
            throw new ServiceException("当前部门存在关联性数据，不允许删除");
        }
    }

    @Override
    public DepartmentVO detail(Long id) {
        SysDepartment sysDepartment = super.getById(id);
        TsfPreconditions.checkArgument(Objects.nonNull(sysDepartment),new ServiceException("部门信息不存在"));
        return beanMapper.map(sysDepartment,DepartmentVO.class);
    }

    @Override
    public List<Long> getSubDepartments(Long id) {
        List<Long> ids = null;
        //获取某部门及其以下所有子部门的部门id列表，包含自己本身
        //查询所有
        List<SysDepartment> allDepartments = super.list();
        if(Objects.isNull(id) || Objects.equals(id,0)) {
            if(CollectionUtil.isNotEmpty(allDepartments)) {
                return allDepartments.stream().map(SysDepartment::getId).collect(Collectors.toList());
            }
        } else {
            List<UIDepartment> trees = UIDepartment.buildTree(allDepartments);
            if(CollectionUtil.isNotEmpty(trees)) {
                //添加自己本身的部门id
                ids = Lists.newArrayList(id);
                //一级节点
                Map<Long, UIDepartment> uiDepartmentMap = trees.stream().collect(Collectors.toMap(UIDepartment::getId, Function.identity()));
                //遍历获取所有的子孙部门,即把所有的子部门也转换成平级
                Map<Long,UIDepartment> firstSubMap = Maps.newHashMap();
                uiDepartmentMap.forEach((k,v)->{
                    UIDepartment.getChildDepartmentMap(firstSubMap,v.getChilds());
                });
                //合并第一级部门map和所有的子部门map
                if(CollectionUtil.isNotEmpty(firstSubMap)) {
                    uiDepartmentMap.putAll(firstSubMap);
                }
                UIDepartment parentUiDepartment = uiDepartmentMap.get(id);
                UIDepartment.getChildDepartmentIds(ids,parentUiDepartment.getChilds());
            }
        }
        return ids;
    }

    @Override
    public SysDepartment findOneByName(String name) {
        if(StringUtils.isEmpty(name)) {
            return null;
        }
        SysDepartment condition = new SysDepartment();
        condition.setName(name);
        return sysDepartmentMapper.selectOne(condition);
    }

}
